/*++

Copyright (c) Microsoft Corporation

Module Name:

    FxDeviceInit.cpp

Abstract:
    Internals for WDFDEVICE_INIT

Author:



Environment:

    Both kernel and user mode

Revision History:

--*/

#include "coreprivshared.hpp"

extern "C" {
#include "FxDeviceInit.tmh"
}

WDFDEVICE_INIT::WDFDEVICE_INIT(
    __in FxDriver* Driver
    ) :
    Driver(Driver)
{
    DriverGlobals = Driver->GetDriverGlobals();

    ReadWriteIoType = WdfDeviceIoBuffered;
    PowerPageable = TRUE;
    Inrush = FALSE;
    DeviceType = FILE_DEVICE_UNKNOWN;
    Characteristics = FILE_DEVICE_SECURE_OPEN;

    RtlZeroMemory(&FileObject, sizeof(FileObject));
    FileObject.AutoForwardCleanupClose = WdfUseDefault;

    DeviceName = NULL;
    CreatedDevice = NULL;

    CreatedOnStack = FALSE;
    Exclusive = FALSE;

    RequiresSelfIoTarget = FALSE;

    RemoveLockOptionFlags = 0;

    RtlZeroMemory(&PnpPower.PnpPowerEventCallbacks, sizeof(PnpPower.PnpPowerEventCallbacks));
    RtlZeroMemory(&PnpPower.PolicyEventCallbacks, sizeof(PnpPower.PolicyEventCallbacks));
    PnpPower.PnpStateCallbacks = NULL;
    PnpPower.PowerStateCallbacks = NULL;
    PnpPower.PowerPolicyStateCallbacks = NULL;

    PnpPower.PowerPolicyOwner = WdfUseDefault;

    InitType = FxDeviceInitTypeFdo;

    RtlZeroMemory(&Fdo.EventCallbacks, sizeof(Fdo.EventCallbacks));
    RtlZeroMemory(&Fdo.ListConfig, sizeof(Fdo.ListConfig));
    RtlZeroMemory(&Fdo.ListConfigAttributes, sizeof(Fdo.ListConfigAttributes));
    Fdo.Filter = FALSE;

    RtlZeroMemory(&Pdo.EventCallbacks, sizeof(Pdo.EventCallbacks));
    Pdo.Raw = FALSE;
    Pdo.Static = FALSE;
    Pdo.DeviceID = NULL;
    Pdo.InstanceID = NULL;
    Pdo.ContainerID = NULL;
    Pdo.DefaultLocale = 0x0;
    Pdo.DescriptionEntry = NULL;
    Pdo.ForwardRequestToParent = FALSE;
    
    RtlZeroMemory(&Security, sizeof(Security));

    RtlZeroMemory(&RequestAttributes, sizeof(RequestAttributes));

    PreprocessInfo = NULL;

    IoInCallerContextCallback = NULL;

    InitializeListHead(&CxDeviceInitListHead);

    ReleaseHardwareOrderOnFailure = WdfReleaseHardwareOrderOnFailureEarly;
    
#if (FX_CORE_MODE == FX_CORE_USER_MODE)

    DeviceControlIoType = WdfDeviceIoBuffered;
    DirectTransferThreshold = 0;

    DevStack = NULL;

    KernelDeviceName = NULL;

    PdoKey = NULL;

    DevInstanceID = NULL;

    DriverID = 0;
#endif
}

WDFDEVICE_INIT::~WDFDEVICE_INIT()
{
    PLIST_ENTRY next;
    
    if (PnpPower.PnpStateCallbacks != NULL) {
        delete PnpPower.PnpStateCallbacks;
    }

    if (PnpPower.PowerStateCallbacks != NULL) {
        delete PnpPower.PowerStateCallbacks;
    }

    if (PnpPower.PowerPolicyStateCallbacks != NULL) {
        delete PnpPower.PowerPolicyStateCallbacks;
    }

    if (DeviceName != NULL) {
        DeviceName->DeleteObject();
    }
    if (Pdo.DeviceID != NULL) {
        Pdo.DeviceID->DeleteObject();
    }
    if (Pdo.InstanceID != NULL) {
        Pdo.InstanceID->DeleteObject();
    }
    if (Pdo.ContainerID != NULL) {
        Pdo.ContainerID->DeleteObject();
    }

    FxDeviceText::_CleanupList(&Pdo.DeviceText);

    if (Security.Sddl != NULL) {
        Security.Sddl->DeleteObject();
    }
    if (PreprocessInfo != NULL) {
        delete PreprocessInfo;
    }

    while(!IsListEmpty(&CxDeviceInitListHead)) {
        next = RemoveHeadList(&CxDeviceInitListHead);
        PWDFCXDEVICE_INIT cxInit;
        cxInit = CONTAINING_RECORD(next, WDFCXDEVICE_INIT, ListEntry);
        InitializeListHead(next);
        delete cxInit;
    }

#if (FX_CORE_MODE == FX_CORE_USER_MODE)
    delete [] KernelDeviceName;
    delete [] ConfigRegistryPath;
    delete [] DevInstanceID;

    if (PdoKey != NULL) {
         RegCloseKey(PdoKey);
         PdoKey = NULL;
    }
#endif

}

_Must_inspect_result_
NTSTATUS
WDFDEVICE_INIT::AssignName(
    __in PFX_DRIVER_GLOBALS FxDriverGlobals,
    __in const UNICODE_STRING* Name
    )
{
    if (DeviceName == NULL) {
        DeviceName = new(FxDriverGlobals, WDF_NO_OBJECT_ATTRIBUTES)
            FxString(FxDriverGlobals);

        if (DeviceName == NULL) {
            NTSTATUS status;

            status = STATUS_INSUFFICIENT_RESOURCES;

            DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
                                "DeviceName is NULL, %!STATUS!", status);

            return status;
        }

        //
        // Clear out the autogenerate flag since we have a specific name
        //
        Characteristics &= ~FILE_AUTOGENERATED_DEVICE_NAME;
    }

    return DeviceName->Assign(Name);
}

_Must_inspect_result_
PWDFDEVICE_INIT
WDFDEVICE_INIT::_AllocateControlDeviceInit(
    __in FxDriver* Driver,
    __in const UNICODE_STRING* SDDLString
    )
{
    PFX_DRIVER_GLOBALS pFxDriverGlobals;
    PWDFDEVICE_INIT pInit;
    NTSTATUS status;

    pFxDriverGlobals = Driver->GetDriverGlobals();

    pInit = new(pFxDriverGlobals) WDFDEVICE_INIT(Driver);

    if (pInit == NULL) {
        DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
                            "WDFDRIVER 0x%p  couldn't allocate WDFDEVICE_INIT",
                            Driver);
        return NULL;
    }

    pInit->InitType = FxDeviceInitTypeControlDevice;

    //
    // Since we require and SDLL string, initialize to autogenerated  device
    // name so the driver doesn't have to worry about creating a name if they
    // don't want it (useful if creating a DO for WMI tracing for instance).
    //
    pInit->Characteristics |= FILE_AUTOGENERATED_DEVICE_NAME;

    pInit->Security.Sddl = new(pFxDriverGlobals, WDF_NO_OBJECT_ATTRIBUTES)
        FxString(pFxDriverGlobals);

    if (pInit->Security.Sddl != NULL) {
        status = pInit->Security.Sddl->Assign(SDDLString);
    }
    else {
        status = STATUS_INSUFFICIENT_RESOURCES;
        DoTraceLevelMessage(
            pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
            "WDFDRIVER 0x%p couldn't create Security String object %!STATUS!",
            Driver, status);
    }

    if (!NT_SUCCESS(status)) {
        delete pInit;
        pInit = NULL;
    }

    return pInit;
}

BOOLEAN
WDFDEVICE_INIT::ShouldCreateSecure(
    VOID
    )
{
    //
    // Driver explicitly set a class or SDDL, we have to create a secure
    // device.  This will be true for all control devices (SDDL required)
    // and raw PDOs (class required), could be true for FDOs or filters as
    // well.
    //
    if (Security.DeviceClassSet || Security.Sddl != NULL) {
        return TRUE;
    }

    //
    // See if there is a name for the device
    //
    if (HasName()) {
        if (IsPdoInit()) {













            ASSERT(Pdo.Raw == FALSE);

            DoTraceLevelMessage(
                DriverGlobals, 
                TRACE_LEVEL_WARNING, 
                TRACINGDEVICE,
                "WDFDRIVER 0x%p asked for a named device object, but the PDO "
                "will be created without a name because an SDDL string has not "
                "been specified for the PDO.",
                Driver
                );
            return FALSE;
        }
        else {
            //
            // We are creating a named FDO or filter
            //
            ASSERT(IsFdoInit());
            return TRUE;
        }
    }

    //
    // No name involved (FDO or filter)
    //
    ASSERT(IsFdoInit());

    return FALSE;
}

VOID
WDFDEVICE_INIT::AddCxDeviceInit(
    __in PWDFCXDEVICE_INIT CxDeviceInit
    )
{
    InsertHeadList(&CxDeviceInitListHead, &CxDeviceInit->ListEntry);
}

